package org.zerta.troops.network;
import org.zerta.troops.common.Game;
import org.zerta.troops.core.TroopsServerBookkeeper;
import org.zerta.troops.server.ServerConsole;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.BindException;

public class TroopsNetworkServer implements Runnable {

	private static final int DEFAULT_SERVER_TCP_PORT = 30666;
	private Game game;
	private Object lock;
	private int port;
	
	private ServerSocket serverSocket;
	private boolean listening;
	private TroopsServerBookkeeper troopsServerBookkeeper;
	private ServerConsole console;

	public TroopsNetworkServer(Game game) {
		startServer(game, DEFAULT_SERVER_TCP_PORT);
	}
	
	public TroopsNetworkServer( Game game, int port ) {
		startServer(game, port);
	}
	
	private boolean startServer( Game game, int port ){
		this.port = port;
		listening = true;
		this.game = game;
		lock = new Object();
		troopsServerBookkeeper = new TroopsServerBookkeeper(this, console);
		try {
			serverSocket = new ServerSocket(port);
			return true;
		} catch (BindException e) {
			System.err.println("Failed setting up server on port " + port + " for game " + game.getName() + ". Unable to bind to port.");
			e.printStackTrace(System.err);
			return false;
		} catch (IOException e) {
			System.err.println("Failed setting up server on port " + port + " for game " + game.getName());
			e.printStackTrace(System.err);
			return false;
		}
	}
	
	public void startBookkeeper() {
		new Thread(troopsServerBookkeeper).start();
	}
	
	public void run() {
		
		console.log("Started server on port " + port);
		while (listening) {
			try {
				Socket socket = serverSocket.accept();
				TroopsClientConnection clientConnection = new TroopsClientConnection(this, game, socket, console);
				new Thread(clientConnection).start();
			} catch (IOException e) {
				System.err.println("Failed setting up client connection");
				e.printStackTrace(System.err);
			}
		}
		try {
			serverSocket.close();
		} catch (IOException e) {
			System.err.println("Failed closing serverSocket");
			e.printStackTrace(System.err);
		}
	}
	
	public void stopServer() {
		listening = false;
	}
	
	public Game getGame() {
		return game;
	}
	
	public Object getLock() {
		return lock;
	}

	public void setConsole(ServerConsole console) {
		this.console = console;
	}

	public ServerConsole getConsole() {
		return console;
	}

}
